#ifndef __socket_H__
#define __socket_H__

#include <boost/type.hpp>
#include <memory>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "address.h"
#include "noncopyable.h"


namespace framework
{

//socket类封装
class Socket : public std::enable_shared_from_this<Socket>, Noncopyable
{
public:
    using ptr = std::shared_ptr<Socket>;
    using weak_ptr = std::weak_ptr<Socket>;

    //socket类型
    enum Type
    {
        TCP = SOCK_STREAM,
        UDP = SOCK_DGRAM
    };

    //socket协议族
    enum Family
    {
        IPv4 = AF_INET,
        IPv6 = AF_INET6,
        UNIX = AF_UNIX
    };

    //创建TCP Socket(满足地址类型)
    static Socket::ptr CreateTCP(framework::Address::ptr address);

    //创建UDP Socket(满足地址类型)
    static Socket::ptr CreateUDP(framework::Address::ptr address);

    //创建IPv4的TCP Socket
    static Socket::ptr CreateTCPSocket();

    //创建IPv4的UDP Socket
    static Socket::ptr CreateUDPSocket();

    //创建IPv6的TCP Socket
    static Socket::ptr CreateTCPSocket6();

    //创建IPv6的UDP Socket
    static Socket::ptr CreateUDPSocket6();

    //创建Unix的TCP Socket
    static Socket::ptr CreateUnixTCPSocket();

    //创建Unix的UDP Socket
    static Socket::ptr CreateUnixUDPSocket();

    //Socket    构造函数
    //family    协议簇
    //type      类型
    //protocol  协议
    Socket(int family, int type, int protocol = 0);

    //析构函数
    virtual ~Socket();

    //获取发送超时时间(毫秒)
    int64_t getSendTimeout();

    //设置发送超时时间(毫秒)
    void setSendTimeout(int64_t v);

    //获取接受超时时间(毫秒)
    int64_t getRecvTimeout();

    //设置接受超时时间(毫秒)
    void setRecvTimeout(int64_t v);

    //获取sockopt  getsockopt
    bool getOption(int level, int option, void* result, socklen_t* len);

    //获取sockopt模板
    template<class T>
    bool getOption(int level, int option, T& result) {
        socklen_t length = sizeof(T);
        return getOption(level, option, &result, &length);
    }

    //设置sockopt  setsockopt
    bool setOption(int level, int option, const void* result, socklen_t len);

    //设置sockopt模板  setsockopt
    template<class T>
    bool setOption(int level, int option, const T& value) {
        return setOption(level, option, &value, sizeof(T));
    }

    /**
     * @brief 接收connect链接
     * @return 成功返回新连接的socket,失败返回nullptr
     * @pre Socket必须 bind , listen  成功
     */
    virtual Socket::ptr accept();

    /**
     * @brief 绑定地址
     * @param[in] addr 地址
     * @return 是否绑定成功
     */
    virtual bool bind(const Address::ptr addr);

    /**
     * @brief 连接地址
     * @param[in] addr 目标地址
     * @param[in] timeout_ms 超时时间(毫秒)
     */
    virtual bool connect(const Address::ptr addr, uint64_t timeout_ms = -1);

    virtual bool reconnect(uint64_t timeout_ms = -1);

    /**
     * @brief 监听socket
     * @param[in] backlog 未完成连接队列的最大长度
     * @result 返回监听是否成功
     * @pre 必须先 bind 成功
     */
    virtual bool listen(int backlog = SOMAXCONN);

    //关闭socket
    virtual bool close();

    /**
     * @brief 发送数据
     * @param[in] buffer 待发送数据的内存
     * @param[in] length 待发送数据的长度
     * @param[in] flags 标志字
     * @return
     *      @retval >0 发送成功对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int send(const void* buffer, size_t length, int flags = 0);

    /**
     * @brief 发送数据
     * @param[in] buffers 待发送数据的内存(iovec数组)
     * @param[in] length 待发送数据的长度(iovec长度)
     * @param[in] flags 标志字
     * @return
     *      @retval >0 发送成功对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int send(const iovec* buffers, size_t length, int flags = 0);

    /**
     * @brief 发送数据
     * @param[in] buffer 待发送数据的内存
     * @param[in] length 待发送数据的长度
     * @param[in] to 发送的目标地址
     * @param[in] flags 标志字
     * @return
     *      @retval >0 发送成功对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int sendTo(const void* buffer, size_t length, const Address::ptr to, int flags = 0);

    /**
     * @brief 发送数据
     * @param[in] buffers 待发送数据的内存(iovec数组)
     * @param[in] length 待发送数据的长度(iovec长度)
     * @param[in] to 发送的目标地址
     * @param[in] flags 标志字
     * @return
     *      @retval >0 发送成功对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int sendTo(const iovec* buffers, size_t length, const Address::ptr to, int flags = 0);

    /**
     * @brief 接受数据
     * @param[out] buffer 接收数据的内存
     * @param[in] length 接收数据的内存大小
     * @param[in] flags 标志字
     * @return
     *      @retval >0 接收到对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int recv(void* buffer, size_t length, int flags = 0);

    /**
     * @brief 接受数据
     * @param[out] buffers 接收数据的内存(iovec数组)
     * @param[in] length 接收数据的内存大小(iovec数组长度)
     * @param[in] flags 标志字
     * @return
     *      @retval >0 接收到对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int recv(iovec* buffers, size_t length, int flags = 0);

    /**
     * @brief 接受数据
     * @param[out] buffer 接收数据的内存
     * @param[in] length 接收数据的内存大小
     * @param[out] from 发送端地址
     * @param[in] flags 标志字
     * @return
     *      @retval >0 接收到对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int recvFrom(void* buffer, size_t length, Address::ptr from, int flags = 0);

    /**
     * @brief 接受数据
     * @param[out] buffers 接收数据的内存(iovec数组)
     * @param[in] length 接收数据的内存大小(iovec数组长度)
     * @param[out] from 发送端地址
     * @param[in] flags 标志字
     * @return
     *      @retval >0 接收到对应大小的数据
     *      @retval =0 socket被关闭
     *      @retval <0 socket出错
     */
    virtual int recvFrom(iovec* buffers, size_t length, Address::ptr from, int flags = 0);


    //获取远端地址
    Address::ptr getRemoteAddress();

    //获取本地地址
    Address::ptr getLocalAddress();

    //获取协议簇
    int getFamily() const { return m_family;}

    //获取类型
    int getType() const { return m_type;}

    //获取协议
    int getProtocol() const { return m_protocol;}

    //返回是否连接
    bool isConnected() const { return m_isConnected;}

    //是否有效(m_sock != -1)
    bool isValid() const;

    //返回Socket错误
    int getError();

    //输出信息到流中
    virtual std::ostream& dump(std::ostream& os) const;
    virtual std::string toString() const;

    //返回socket文件描述符
    int getSocket() const { return m_sock;}

    //取消读
    bool cancelRead();

    //取消写
    bool cancelWrite();

    //取消accept
    bool cancelAccept();

    //取消所有事件
    bool cancelAll();

protected:

    //初始化socket 设置sock参数
    void initSock();

    //创建socket
    void newSock();

    //初始化sock
    virtual bool init(int sock);

protected:

    int     m_sock;              //socket文件描述符
    int     m_family;            //协议族  AF_INET  AF_INET6
    int     m_type;              //类型    SOCK_STREAM(可靠) SOCK_DGRAM（不可靠）
    int     m_protocol;          //协议    IPPROTO_TCP       IPPROTO_UDP  
    bool    m_isConnected;       //是否链接
    Address::ptr m_localAddress; //本地地址
    Address::ptr m_remoteAddress;//远端地址

};


class SSLSocket: public Socket
{
public:
using ptr = std::shared_ptr<SSLSocket>;

private:
};

/**
 * @brief 流式输出socket
 * @param[in, out] os 输出流
 * @param[in] sock Socket类
 */
std::ostream& operator<<(std::ostream& os, const Socket& sock);
  
} // namespace framework





#endif
